package com.yuandian.customer.perception.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuandian.api.customer_perception.po.BusinessAnalysisParams;
import com.yuandian.api.customer_perception.po.BusinessComparativeAnalysisParams;
import com.yuandian.api.customer_perception.vo.*;
import com.yuandian.api.management.feign.RemoteStepService;
import com.yuandian.base.service.ITaskDataService;
import com.yuandian.bpm.common.core.constant.CommonConstants;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.customer.perception.mapper.BusinessAnalysisMapper;
import com.yuandian.customer.perception.service.IBusinessAnalysisService;
import com.yuandian.enums.TableNameEnum;
import com.yuandian.po.MergeDataConfig;
import com.yuandian.po.MergeField;
import com.yuandian.po.MultipleTableInfo;
import com.yuandian.utils.DynamicTableNameUtil;
import com.yuandian.utils.MergeDataUtil;
import com.yuandian.utils.PageDataInfo;
import com.yuandian.utils.pool.ExecutorUtils;
import com.yuandian.vo.TrendDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;

/**
 * 说明：业务分析service实现
 * @Author LinShiHe
 * @Date 2021/8/11 13:37
 */
@Slf4j
@Service
public class BusinessAnalysisServiceImpl implements IBusinessAnalysisService {

    @Autowired
    private BusinessAnalysisMapper businessAnalysisMapper;

    @Autowired
    private RemoteStepService remoteStepService;

    @Autowired
    private ITaskDataService taskDataService;


    private static final ExecutorService threadPool = ExecutorUtils.defaultThreadPool();

    /**
     * 查询业务分析概况
     * @param params 请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryBusinessAnalysisOverview(BusinessAnalysisParams params) {
        // 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
        List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

        // 设置表信息集，默认排序
        params.setMultipleTableInfoList(newMultipleTableInfoList);

        // 查询分析指标
        BusinessAnalysisOverviewVo vo = businessAnalysisMapper.queryBusinessAnalysisOverview(params);

        return  R.ok(vo);
    }

    /**
     * 查询业务告警占比
     * @param params 系统分析请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryBusinessAlarmProportion(BusinessAnalysisParams params) {
        // 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.MYSQL_BUSI_BASE_ALARM_STAT.getName());
		List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
		params.setMultipleTableInfoList(newMultipleTableInfoList);

		// 执行查询
        List<BusinessAlarmProportionVo> voList = businessAnalysisMapper.queryBusinessAlarmProportion(params);

        return  R.ok(voList);
    }

    /**
     * 查询业务指标趋势
     * 业务健康度,平均办理时长,平均响应时长-busi_sys_detail_stat_m-KhgzBusinessDetailStatTask-业务指标趋势-延迟3分钟-//api-khgz/modules/business/analysis/queryBusinessIndicatorTrend
     * @param params 业务分析请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryBusinessIndicatorTrend(BusinessAnalysisParams params) {
		// 获取表信息集
		MultipleTableInfo info = DynamicTableNameUtil.generalSingleTableNamesFromTimeRange(params.getStartTime(), params.getEndTime());
		List<String> tableNameList = Collections.singletonList(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());

        // 设置表名、时间范围矫正
        params.setTableNameList(tableNameList);

        // 执行查询
        List<BusinessIndicatorTrendVo> res = businessAnalysisMapper.queryBusinessIndicatorTrend(params);

        // 归并数据
        Integer minScale = DynamicTableNameUtil.getMinScaleByTableType(info.getTableType());
        Integer scale = null;
        if (params.getScale() != null) {
            scale = DynamicTableNameUtil.getScaleByMinScaleAndParam(minScale, params.getScale());
        }
        List<MergeField> mergeFieldList = new ArrayList<>();
        if (params.getType()==1){
            mergeFieldList.add(new MergeField("visitCount"));
            mergeFieldList.add(new MergeField("alarmCount"));
            mergeFieldList.add(new MergeField("totalVisitTime"));
            mergeFieldList.add(new MergeField("totalServerResponseTime"));
        }else{
            mergeFieldList.add(new MergeField("visitCount"));
            mergeFieldList.add(new MergeField("completeCount"));
            mergeFieldList.add(new MergeField("failCount"));
            mergeFieldList.add(new MergeField("alarmCount"));
        }


        Map<String, Object> map = MergeDataUtil.mergeData(new MergeDataConfig.Builder(
                BusinessIndicatorTrendVo.class,
                res,
                params.getStartTime(),
                params.getEndTime(),
                mergeFieldList)
                .cycleTimeKey("cycleTime")
                .labelTimeFormatter("MM-dd'\n'HH:mm")
                .scale(scale)
                .build());
        map.put("minScale", minScale);
        if (params.getType()==1){
            Map<String, List<Double>> resFieldMap = (Map<String, List<Double>>) map.get("resFieldMap");
            List<Double> visitCountList = resFieldMap.get("visitCountList");
            List<Double> totalServerResponseTimeList = resFieldMap.get("totalServerResponseTimeList");
            List<Double> list = new ArrayList<>();
            for (int i = 0; i < visitCountList.size(); i++) {
                if (totalServerResponseTimeList.get(i)==0){
                    list.add(0.00);
                }else{
                    list.add(Double.valueOf(String.format("%.2f", (totalServerResponseTimeList.get(i)/visitCountList.get(i))/(scale/60))));
                }

            }
            resFieldMap.put("avgServerResponseTimeList", list);

            List<Double> totalVisitTimeList = resFieldMap.get("totalVisitTimeList");
            List<Double> avgVisitTimeList = new ArrayList<>();
            for (int i = 0; i < visitCountList.size(); i++) {

                if (totalVisitTimeList.get(i)==0){
                    avgVisitTimeList.add(0.00);
                }else{
                    avgVisitTimeList.add(Double.valueOf(String.format("%.2f", (totalVisitTimeList.get(i)/visitCountList.get(i))/(scale/60))));
                }
            }
            resFieldMap.put("avgVisitTimeList", avgVisitTimeList);

            List<Double> alarmCountList = resFieldMap.get("alarmCountList");
            List<Double> avgHealthRateList = new ArrayList<>();
            for (int i = 0; i < visitCountList.size(); i++) {
                if (visitCountList.get(i)==0){
                    avgHealthRateList.add(0.00);
                }else{
                    avgHealthRateList.add(Double.valueOf(String.format("%.2f", ((visitCountList.get(i)-alarmCountList.get(i))/visitCountList.get(i))*100)));
                }
            }
            resFieldMap.put("avgHealthRateList", avgHealthRateList);
//


        }

        // 3、处理时间标签
        TrendDataVo trendDataVo = taskDataService.getTrendObject("KHGZ-详单分钟统计", params.getStartTime(), params.getEndTime(), map);
        return  R.ok(trendDataVo);
    }

    /**
     * 业务步骤分析列表
     * @param params 请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryBusinessStepAnalysisList(BusinessAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.MYSQL_BUSI_STEP_STAT.getName());
		List<MultipleTableInfo> multipleTableInfoList = Collections.singletonList(info);


		// 设置表信息集，默认排序
        params.setMultipleTableInfoList(multipleTableInfoList);
        // 执行查询
        Page<BusinessStepAnalysisVo> page = new Page<>(params.getPageNum(), params.getPageSize());
        List<BusinessStepAnalysisVo> resList = new ArrayList<>();
        List<BusinessStepAnalysisVo> stepList;
        List<BusinessStepAnalysisVo> analysisVoList;

        // 默认按照业务步骤的顺序排序
        if (StringUtils.isEmpty(params.getOrderByColumn()) || "stepName".equals(params.getOrderByColumn())) {
            // 根据业务查询步骤列表
            R<List<BusinessStepAnalysisVo>> stepList1 = remoteStepService.selectStepsByBusicessCode(params);
            if (stepList1.getCode() == CommonConstants.FAIL) {
                log.error("远程调用配置系统获取获取业务步骤数据失败，错误：{}", stepList1.getMsg());
            }
            stepList = stepList1.getData();
            // 查询结果
            analysisVoList = businessAnalysisMapper.queryBusinessStepAnalysisList(params);
            // 封装数据
            if (stepList != null && stepList.size() > 0) {
                for (BusinessStepAnalysisVo stepVo : stepList) {
                    for (BusinessStepAnalysisVo analysisVo : analysisVoList) {
                        if (stepVo.getStepCode().equals(analysisVo.getStepCode())) {
                            resList.add(analysisVo);
                            break;
                        }
                    }
                }
            }
        }else {
            // 其他字段排序
            R<List<BusinessStepAnalysisVo>> stepList1 = remoteStepService.selectStepsByBusicessCode(params);
            if (stepList1.getCode() == CommonConstants.FAIL) {
                log.error("远程调用配置系统获取获取业务步骤数据失败，错误：{}", stepList1.getMsg());
            }
            stepList = stepList1.getData();
            // 分页查询对应结果
            analysisVoList = businessAnalysisMapper.queryBusinessStepAnalysisPageList(params, page);
            // 封装数据
            if (analysisVoList != null && analysisVoList.size() > 0) {
                for (BusinessStepAnalysisVo analysisVo : analysisVoList) {
                    for (BusinessStepAnalysisVo stepVo : stepList) {
                        if (stepVo.getStepCode().equals(analysisVo.getStepCode())) {
                            resList.add(analysisVo);
                            break;
                        }
                    }
                }
            }
        }

        return  R.ok(new PageDataInfo(page, resList));
    }

    /**
     * 业务步骤分析列表下载
     * @param params 请求参数
     * @return 通用返回对象
     */
    @Override
    public List<BusinessStepAnalysisVo> queryBusinessStepAnalysisListExport(BusinessAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.MYSQL_BUSI_STEP_STAT.getName());
		List<MultipleTableInfo> multipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
        params.setMultipleTableInfoList(multipleTableInfoList);

        // 执行查询
        List<BusinessStepAnalysisVo> resList = new ArrayList<>();
        List<BusinessStepAnalysisVo> stepList;
        List<BusinessStepAnalysisVo> analysisVoList = new ArrayList<>();

         // 根据业务查询步骤列表
        R<List<BusinessStepAnalysisVo>> stepList1 = remoteStepService.selectStepsByBusicessCode(params);
        if (stepList1.getCode() == CommonConstants.FAIL) {
            log.error("远程调用配置系统获取获取业务步骤数据失败，错误：{}", stepList1.getMsg());
        }
        stepList = stepList1.getData();
        // 查询结果
        analysisVoList = businessAnalysisMapper.queryBusinessStepAnalysisList(params);

        if (StringUtils.isEmpty(params.getOrderByColumn()) || "stepName".equals(params.getOrderByColumn())) {
            // 封装数据（默认按照业务步骤的顺序排序）
            if (stepList != null && stepList.size() > 0) {
                for (BusinessStepAnalysisVo stepVo : stepList) {
                    for (BusinessStepAnalysisVo analysisVo : analysisVoList) {
                        if (stepVo.getStepCode().equals(analysisVo.getStepCode())) {
                            resList.add(analysisVo);
                            break;
                        }
                    }
                }
            }
        }else {
            // 封装数据(按照其他字段排序)
            if (analysisVoList != null && analysisVoList.size() > 0) {
                for (BusinessStepAnalysisVo analysisVo : analysisVoList) {
                    for (BusinessStepAnalysisVo stepVo : stepList) {
                        if (stepVo.getStepCode().equals(analysisVo.getStepCode())) {
                            resList.add(analysisVo);
                            break;
                        }
                    }
                }
            }
        }

        return resList;
    }

    /**
     * 分页查询业务操作员总览
     * @param params 请求参数
     * @return 通用分页对象
     */
    @Override
    public R<Object> queryBusinessOperatorOverview(BusinessAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> multipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
        params.setMultipleTableInfoList(multipleTableInfoList);

        // 执行查询
        Page<BusinessOperatorOverviewVo> page = new Page<>(params.getPageNum(), params.getPageSize());
        List<BusinessOperatorOverviewVo> voList = businessAnalysisMapper.queryBusinessOperatorOverview(params, page);

        return  R.ok(new PageDataInfo(page, voList));
    }

    /**
     * 分页查询业务操作员总览下载
     * @param params 请求参数
     * @return 通用分页对象
     */
	@Override
    public List<BusinessOperatorOverviewVo> queryBusinessOperatorOverviewExport(BusinessAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> multipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
        params.setMultipleTableInfoList(multipleTableInfoList);

        // 执行查询
        List<BusinessOperatorOverviewVo> voList = businessAnalysisMapper.queryBusinessOperatorOverviewExport(params);

        return voList;
    }


    /**
     * 查询操作员业务办理量TOPN
     * @param params 请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryOperatorCompleteTopN(BusinessAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> multipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
        params.setMultipleTableInfoList(multipleTableInfoList);

        // 执行查询
        List<OperatorCompleteTopNVo> voList = businessAnalysisMapper.queryOperatorCompleteTopN(params);

		return  R.ok(voList);
    }


    /**
     * 查询营业员办理业务告警类型分布
     * @param params 请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryOperatorBusinessAlarm(BusinessAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.MYSQL_BUSI_BASE_ALARM_STAT.getName());
		List<MultipleTableInfo> multipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
        params.setMultipleTableInfoList(multipleTableInfoList);

        // 执行查询
        List<OperatorBusinessAlarmVo> voList = businessAnalysisMapper.queryOperatorBusinessAlarm(params);

        return  R.ok(voList);
    }

    /**
     * 查询性能指标概况列表
     * @param paramsList 业务对比分析请求对象集合
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryPerformanceIndexSurvey(List<BusinessComparativeAnalysisParams> paramsList) {
        int len = paramsList.size();
        CountDownLatch countDownLatch = new CountDownLatch(len);
        // 1、开启多线程查询多组数据
        List<BusinessComparativeAnalysisVo> list = new ArrayList<>(len);
        for (int i = 0; i < len; i++) {
            BusinessComparativeAnalysisParams params = paramsList.get(i);
            final int count = i;
            threadPool.execute(() -> {
                try {
                    // 1.1、设置表名
                    String tableName = TableNameEnum.MYSQL_BUSI_SYS_DETAIL_STAT_M.getName();
                    if (StringUtils.isEmpty(tableName)) {
                        list.add(count, null);
                        return;
                    }
                    params.setTableName(tableName);
                    // 1.2、执行查询
                    BusinessComparativeAnalysisVo vo = businessAnalysisMapper.queryPerformanceIndexSurvey(params);
                    list.add(count, vo);
                } catch (Exception e) {
                    log.error("查询性能指标概况列表异常, {}", e.getMessage());
                    list.add(count, null);
                } finally {
                    // 保证不会被阻塞
                    countDownLatch.countDown();
                }
            });
        }

        // 2、阻塞当前线程
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error("阻塞异常");
        }

        // 3、数据对比处理
        if (list.size() <= 1) {
            return  R.ok(list);
        }
        BusinessComparativeAnalysisVo baseVo = list.get(0);
        if (baseVo == null) {
            return  R.ok(list);
        }
        for (int i = 1; i < list.size(); i++) {
            BusinessComparativeAnalysisVo vo = list.get(i);
            if (vo == null) {
                continue;
            }
            vo.setVisitCountStatus(calcuPerformanceStatus(
                    (double) baseVo.getVisitCount(), (double) vo.getVisitCount()));
            vo.setCompleteCountStatus(calcuPerformanceStatus(
                    (double) baseVo.getCompleteCount(), (double) vo.getCompleteCount()));
            vo.setAlarmCountStatus(calcuPerformanceStatus(
                    (double) baseVo.getAlarmCount(), (double) vo.getAlarmCount()));
            vo.setFailCountStatus(calcuPerformanceStatus(
                    (double) baseVo.getFailCount(), (double) vo.getFailCount()));
            vo.setAvgVisitTimeStatus(calcuPerformanceStatus(
                    baseVo.getAvgVisitTime(), vo.getAvgVisitTime()));
            vo.setAvgDealTimeStatus(calcuPerformanceStatus(
                    baseVo.getAvgDealTime(), vo.getAvgDealTime()));
            vo.setAvgServerResponseTimeStatus(calcuPerformanceStatus(
                    baseVo.getAvgServerResponseTime(), vo.getAvgServerResponseTime()));
            vo.setHealthRateStatus(calcuPerformanceStatus(
                    baseVo.getHealthRate(), vo.getHealthRate()));
            vo.setSuccessRateStatus(calcuPerformanceStatus(
                    baseVo.getSuccessRate(), vo.getSuccessRate()));
        }
        return  R.ok(list);
    }

    private double calcuPerformanceStatus(double d1, double d2) {
        if (d2 <= 0) {
            return 0.00d;
        }
        return new BigDecimal(((d1 / d2) - 1) * 100)
                    .setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

}
